home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / libraris / sregexp1 / part02 / sregexp.c < prev    next >
C/C++ Source or Header  |  1992-04-20  |  17KB  |  663 lines

  1.  
  2. /* This is a routine to test if a string matches a regular expression.
  3.  *
  4.  *
  5.  *  The regular expression sytax is a slight extension of the regular
  6.  * AmigaDos wildcard patterns. Apparently 2.0 has added a few new things
  7.  * (well, at least a not operator) to the game.  This may or may not
  8.  * be consistant with those additions (it's the way they otta done it.)
  9.  *
  10.  * Here it is:
  11.  *
  12.  *    ?        matches any one character
  13.  *
  14.  *    #(pat)      matches zero or more occurances of the pattern pat.
  15.  *
  16.  *    (pat)       seperates out a piece of the pattern.
  17.  *
  18.  *    pat1|pat2   matches to either pat1 or pat2
  19.  *
  20.  *    '           escapes the special meaning of these symbols.
  21.  *
  22.  *    %        matches the null string.
  23.  *
  24.  *  EXTENSIONS
  25.  *
  26.  *    [chars]     will match any single character in the set chars,
  27.  *            specified as single characters or ranges seperated
  28.  *            by a -.  Ex. [af-i+] would match a, f, g, h, i, and
  29.  *            +.    If ~ is the first character in the set then the
  30.  *            set matched is the complement of the set specified.
  31.  *            Ex. [~a-z] would match any one character that is
  32.  *            not a (lower case if case sensitivity is on) letter.
  33.  *            Note that a [~a] is NOT the same as a ~[a]. The former
  34.  *            would match a 'b' but not a 'ab', whereas the latter
  35.  *            would match both.
  36.  *
  37.  *    ~(pat)      will match anything that doesn't match the pattern.
  38.  *            Note: it is illegal to repeat a not. ie #~a is illegal.
  39.  *            (So is #(~(a)) so don't even try it.) You can repeat
  40.  *            something with a not IN it, as long as it can't be
  41.  *            reduced to the form #~(pattern). (A #[~a] is OK.)
  42.  *            However ~#a has the expected effect (matches any
  43.  *            non-null string not composed entirely of a's.)
  44.  *
  45.  *    *        same as #?.
  46.  *
  47.  *
  48.  */
  49.  
  50. #include "sregexp.h"
  51.  
  52. const char wilds[] = {          /* string of the wildcards, for easy access */
  53.             CHR_REPEAT,
  54.             CHR_NOT,
  55.             CHR_OPENBRACE,
  56.             CHR_CLOSEBRACE,
  57.             CHR_OPENSET,
  58.             CHR_CLOSESET,
  59.             CHR_ANYCHAR,
  60.             CHR_NULL,
  61.             CHR_OR,
  62.             CHR_ESCAPE,
  63. /*            CHR_RANGE,     <--- special case  */
  64.             CHR_STAR,
  65.             0
  66. };
  67.  
  68. #ifdef __DEBUG__
  69. extern void puts(char *);
  70. extern void printf(char *, ...);
  71. #endif
  72.  
  73.  
  74. struct SregExp *
  75. parsesregexp(expr)
  76. char *expr;
  77. /* This is the entry point into the parsing subroutines. */
  78. {
  79.     return parsesub(&expr,0);
  80. }
  81.  
  82. static struct SregExp *
  83. parsesub(p,end)
  84. char **p,end;
  85. /* This routine will parse a sub expression up until the character
  86.    'end' is encontered.  This is 0 for the whole pattern and ')'
  87.    for a subpattern */
  88. {
  89.     struct SregList *list,*head=NULL,*orlist,*orhead=NULL;
  90.     struct SregExp *sreg;
  91.     int num = 0,ornum = 0;
  92.  
  93.     while (**p != end) {
  94.     if (**p == CHR_OR) {            /* deal with stuff like (ab||cd) == (ab|%|cd) */
  95.         if (!(sreg = makenull()))
  96.         goto cleanup;
  97.     } else {
  98.         if (!(sreg = parseone(p,TRUE)))  /* parse one wildcard */
  99.         goto cleanup;
  100.     }
  101.     if (head) {     /* if there's already a list, just stick it on */
  102.         if (!(list = (list->srl_next = getmem(sizeof(struct SregList))))) {
  103.         report(MEM_ERROR);
  104.         goto cleanup;
  105.         }
  106.     } else {    /* otherwise, make a new list */
  107.         if (!(list = (head = getmem(sizeof(struct SregList))))) {
  108.         report(MEM_ERROR);
  109.         goto cleanup;
  110.         }
  111.     }
  112.     list->srl_sreg = sreg;
  113.     list->srl_next = NULL;
  114.     num++;
  115.     if (**p == CHR_OR) {        /* deal with an or */
  116.         if (!(sreg = makesum(head,num)))
  117.         goto cleanup;
  118.         if (orhead) {           /* either add onto the or list */
  119.         if (!(orlist = (orlist->srl_next = getmem(sizeof(struct SregList))))) {
  120.             report(MEM_ERROR);
  121.             goto cleanup;
  122.         }
  123.         } else {            /* or make a new or list */
  124.         if (!(orlist = (orhead = getmem(sizeof(struct SregList))))) {
  125.             report(MEM_ERROR);
  126.             goto cleanup;
  127.         }
  128.         }
  129.         orlist->srl_sreg = sreg;
  130.         orlist->srl_next = NULL;
  131.         ornum++;
  132.         (*p)++;
  133.         head = NULL;
  134.         num = 0;
  135.     }
  136.     }
  137.     if (head) {
  138.     if (!(sreg = makesum(head,num)))
  139.         goto cleanup;
  140.     } else {
  141.     if (!(sreg = makenull()))
  142.         goto cleanup;
  143.     }
  144.     head = NULL;
  145.     if (orhead) {       /* if this expression had an or, clean it up */
  146.     if (!(orlist = (orlist->srl_next = getmem(sizeof(struct SregList))))) {
  147.         report(MEM_ERROR);
  148.         freesregexp(sreg);
  149.         goto cleanup;
  150.     }
  151.     orlist->srl_sreg = sreg;
  152.     orlist->srl_next = NULL;
  153.     ornum++;
  154.     if (!(sreg = makeor(orhead,ornum)))
  155.         goto cleanup;
  156.     }
  157.  
  158.     return sreg;    /* sub expression successfully matched. */
  159.  
  160. cleanup:    /* troubles all head here to clean up */
  161.  
  162.     list = head;
  163.     while (list) {          /* free all the bits of the current sum */
  164.     head = list->srl_next;
  165.     freesregexp(list->srl_sreg);
  166.     freemem(list,sizeof(struct SregList));
  167.     list = head;
  168.     }
  169.     list = orhead;
  170.     while (list) {          /* and all of the current or parts */
  171.     head = list->srl_next;
  172.     freesregexp(list->srl_sreg);
  173.     freemem(list,sizeof(struct SregList));
  174.     list = head;
  175.     }
  176.  
  177.     return NULL;        /* return the failure */
  178. }
  179.  
  180. static struct SregExp *
  181. makesum(list,num)
  182. struct SregList *list;
  183. int num;
  184. /* This routine takes a linked list of sreg's and joins them together
  185.    Under the auspices of one big SRP_SUM type sreg */
  186. {
  187.     struct SregList *lnk;
  188.     struct SregExp *sreg;
  189.     int i,len=0;
  190.     char fixed = SRF_FIXLEN;
  191.  
  192.     if (num == 0) {
  193.     report(ILLEGAL_ERR);
  194.     return NULL;
  195.     } else if (num == 1) {
  196.     sreg = list->srl_sreg;
  197.     freemem(list,sizeof(struct SregList));
  198.     return sreg;
  199.     } if (!(sreg = getmem(sizeof(struct SregExp) + num*sizeof(struct SregExp *)))) {
  200.     report(MEM_ERROR);
  201.     return NULL;
  202.     }
  203.     sreg->sre_Type = SRP_SUM;
  204.     sreg->sre_Flag = 0;
  205.     sreg->sre_Data.number = num;
  206.     for (i = 0; i < num; i++) {
  207.     len += realen(list->srl_sreg);
  208.     fixed &= isfixed(list->srl_sreg) ? SRF_FIXLEN : 0;
  209.     sreg->sre_List[i] = list->srl_sreg;
  210.     lnk = list->srl_next;
  211.     freemem(list,sizeof(struct SregList));
  212.     list = lnk;
  213.     }
  214.     sreg->sre_MinLen = len;
  215.     sreg->sre_Flag |= fixed;
  216.     return sreg;
  217. }
  218.  
  219. static struct SregExp *
  220. makeor(list,num)
  221. struct SregList *list;
  222. int num;
  223. /* This does basically the same thing as makesum, except it makes
  224.    an SRP_OR type sreg to join the list and doesn't deal with some
  225.    special cases */
  226. {
  227.     struct SregList *lnk;
  228.     struct SregExp *sreg;
  229.     int i,len;
  230.     char fixed = SRF_FIXLEN;
  231.  
  232.     if (!(sreg = getmem(sizeof(struct SregExp) + num*sizeof(struct SregExp *)))) {
  233.     report(MEM_ERROR);
  234.     return NULL;
  235.     }
  236.     sreg->sre_Type = SRP_OR;
  237.     sreg->sre_Flag = 0;
  238.     sreg->sre_Data.number = num;
  239.     for (i = 0; i < num; i++) {
  240.     if (i == 0)
  241.         len = realen(list->srl_sreg);
  242.     else if (len != realen(list->srl_sreg)) {
  243.         fixed = 0;
  244.         if (len > realen(list->srl_sreg))
  245.         len = realen(list->srl_sreg);
  246.     }
  247.     fixed &= isfixed(list->srl_sreg) ? SRF_FIXLEN : 0;
  248.     sreg->sre_List[i] = list->srl_sreg;
  249.     lnk = list->srl_next;
  250.     freemem(list,sizeof(struct SregList));
  251.     list = lnk;
  252.     }
  253.     sreg->sre_MinLen = len;
  254.     sreg->sre_Flag |= fixed;
  255.     return sreg;
  256. }
  257.  
  258. static struct SregExp *
  259. parseone(p,cat)
  260. char **p,cat;
  261. /* This routine parses one wildcard character from the string *p,
  262.    leaving it set up pointing to the begining of the next
  263.    wildcard. If 'cat' is true then a string of characters will
  264.    be grouped together as a SRP_STRING type sreg.  It may be
  265.    false because of the scope rules of ~ and #, which only
  266.    repeat the very next pattern. */
  267. {
  268.     struct SregExp *sreg;
  269.  
  270.     switch (**p) {
  271.     case (CHR_REPEAT) :
  272.         (*p)++;
  273.         if (!(sreg = parseone(p,FALSE)))
  274.         return NULL;
  275.         if (sreg->sre_Flag & SRF_NOT) {
  276.         report(ILLEGAL_ERR);
  277.         freesregexp(sreg);
  278.         return NULL;
  279.         }
  280.         sreg->sre_Flag |= SRF_REPEAT;
  281.         break;
  282.     case (CHR_NOT) :
  283.         (*p)++;
  284.         if (!(sreg = parseone(p,FALSE)))
  285.         return NULL;
  286.         sreg->sre_Flag |= SRF_NOT;
  287.         break;
  288.     case (CHR_OPENBRACE) :
  289.         (*p)++;
  290.         sreg = parsesub(p,CHR_CLOSEBRACE);
  291.         (*p)++;
  292.         break;
  293.     case (CHR_OPENSET) :
  294.         (*p)++;
  295.         if (!(sreg = getmem(sizeof(struct SregExp)))) {
  296.         report(MEM_ERROR);
  297.         return NULL;
  298.         }
  299.         sreg->sre_Type = SRP_SETCHAR;
  300.         sreg->sre_Flag = SRF_FIXLEN;
  301.         sreg->sre_MinLen = 1;
  302.         if (!(sreg->sre_Data.setchar = makeset(p))) {
  303.         freemem(sreg,sizeof(sreg));
  304.         return NULL;
  305.         }
  306.         (*p)++;
  307.         break;
  308.     case (CHR_ANYCHAR) :
  309.         (*p)++;
  310.         if (!(sreg = getmem(sizeof(struct SregExp)))) {
  311.         report(MEM_ERROR);
  312.         return NULL;
  313.         }
  314.         sreg->sre_Type = SRP_ANYCHAR;
  315.         sreg->sre_Flag = SRF_FIXLEN;
  316.         sreg->sre_MinLen = 1;
  317.         break;
  318.     case (CHR_STAR) :
  319.         (*p)++;
  320.         if (!(sreg = getmem(sizeof(struct SregExp)))) {
  321.         report(MEM_ERROR);
  322.         return NULL;
  323.         }
  324.         sreg->sre_Type = SRP_ANYCHAR;
  325.         sreg->sre_Flag = SRF_FIXLEN | SRF_REPEAT;
  326.         sreg->sre_MinLen = 1;
  327.         break;
  328.     case (CHR_NULL) :
  329.         (*p)++;
  330.         if (!(sreg = makenull()))
  331.         return NULL;
  332.         break;
  333.     case (CHR_CLOSEBRACE) :
  334.     case (CHR_CLOSESET) :
  335.     case (CHR_OR) :
  336.     case (0) :
  337.         report(ILLEGAL_ERR);
  338.         return NULL;
  339.     default :
  340.         if (!(sreg = getmem(sizeof(struct SregExp)))) {
  341.         report(MEM_ERROR);
  342.         return NULL;
  343.         }
  344.         sreg->sre_Flag = SRF_FIXLEN;
  345.         if (!cat) {
  346.         sreg->sre_Data.onechar = onechar(p,FALSE);
  347.         sreg->sre_Type = SRP_ONECHAR;
  348.         sreg->sre_MinLen = 1;
  349.         } else {
  350.         char *q=*p;
  351.         int len=0;
  352.  
  353.         while (onechar(&q,FALSE))
  354.             len++;
  355.         sreg->sre_MinLen = len;
  356.         if (len == 1) {
  357.             sreg->sre_Data.onechar = onechar(p,FALSE);
  358.             sreg->sre_Type = SRP_ONECHAR;
  359.         } else {
  360.             sreg->sre_Type = SRP_STRING;
  361.             if (!(q = sreg->sre_Data.string = getmem(len+1))) {
  362.             report(MEM_ERROR);
  363.             freemem(sreg,sizeof(sreg));
  364.             return NULL;
  365.             }
  366.             while (*q++ = onechar(p,FALSE)) ;
  367.         }
  368.         }
  369.     }
  370.     return sreg;
  371. }
  372.  
  373. static struct SregExp *
  374. makenull()
  375. /* This routine makes an node matching the null string. */
  376. {
  377.     struct SregExp *sreg;
  378.  
  379.     if (!(sreg = getmem(sizeof(struct SregExp)))) {
  380.     report(MEM_ERROR);
  381.     return NULL;
  382.     }
  383.     sreg->sre_Type = SRP_NULL;
  384.     sreg->sre_Flag = SRF_FIXLEN;
  385.     sreg->sre_MinLen = 0;
  386. }
  387.  
  388. static char
  389. onechar(p,minus)
  390. char **p,minus;
  391. /* this routine picks one character off the string *p.    It handles
  392.    escaping the special meaning of the wildcard characters, and
  393.    returns 0 if we're at the end of the string or the next
  394.    char is a wildcard.    if 'minus' is true, then the '-' is
  395.    treated as a wildcard, otherwise it isn't */
  396. {
  397.     if (**p == CHR_ESCAPE)
  398.     (*p)++;
  399.     else if (strchr(wilds,**p) || (minus && **p == CHR_RANGE))
  400.     return 0;
  401.     return *(*p)++;
  402. }
  403.  
  404. static char *
  405. makeset(p)
  406. char **p;
  407. /* this makes a table of match flags from the character specifier
  408.    that goes in between [ and ].  It handles a leading '~' and
  409.    leaves *p pointing to the closing brace. Note: This routine
  410.    checks to make sure the specifier ends in a ] and fails if
  411.    it doesn't */
  412. {
  413.     char *set,not=FALSE,ok=FALSE,s,e;
  414.  
  415.     if (**p == CHR_NOT) {
  416.     (*p)++;
  417.     not = TRUE;
  418.     }
  419.     if (!(set = getmem(32))) {
  420.     report(MEM_ERROR);
  421.     return NULL;
  422.     }
  423.     for (s = 0; s < 32; s++)
  424.     set[s] = 0;
  425.     while (s = onechar(p,TRUE)) {
  426.     ok = TRUE;
  427.     if (**p == CHR_RANGE) {
  428.         (*p)++;
  429.         if (!(e = onechar(p,TRUE))) {
  430.         report(ILLEGAL_ERR);
  431.         freemem(set,32);
  432.         return NULL;
  433.         }
  434.         for ( ; s <= e; s++)
  435.         set[s/8] |= 1 << (s % 8);
  436.     } else
  437.         set[s/8] |= 1 << (s % 8);
  438.     }
  439.     if (!ok || **p != CHR_CLOSESET) {
  440.     report(ILLEGAL_ERR);
  441.     freemem(set,32);
  442.     return NULL;
  443.     }
  444.     if (not) {
  445.     for(s = 0; s < 32; s++)
  446.         set[s] = ~set[s];
  447.     }
  448.     return set;
  449. }
  450.  
  451. void
  452. freesregexp(sreg)
  453. struct SregExp *sreg;
  454. /* this routine frees up a sreg.  It correctly handles freeing the
  455.    subpattern elements in a SRP_SUM or SRP_OR sreg and frees the
  456.    match table or string from a SRP_SETCHAR or SRP_STRING sreg.
  457.    This is one of the externally visible routines. */
  458. {
  459.     int add = 0;
  460.  
  461.     if (sreg->sre_Type == SRP_SUM || sreg->sre_Type == SRP_OR) {
  462.     int i;
  463.  
  464.     add = sreg->sre_Data.number * sizeof(struct SregExp *);
  465.     for (i = 0; i < sreg->sre_Data.number; i++)
  466.         freesregexp(sreg->sre_List[i]);
  467.  
  468.     } else if (sreg->sre_Type == SRP_STRING)
  469.     freemem(sreg->sre_Data.string,strlen(sreg->sre_Data.string)+1);
  470.     else if (sreg->sre_Type == SRP_SETCHAR)
  471.     freemem(sreg->sre_Data.setchar,32);
  472.     freemem(sreg,sizeof(struct SregExp) + add);
  473. }
  474.  
  475. int
  476. matchsregexp(p,sreg,up)
  477. char *p;
  478. struct SregExp *sreg;
  479. int up;
  480. /* This is the externally visible stub to the pattern matching part
  481.    of sreg.  'p' is the string to match to, sreg is the preparsed
  482.    sreg, and up indicates if the match is case sensitive. */
  483. {
  484.     return matchnsregexp(p,sreg,up,strlen(p));
  485. }
  486.  
  487. int
  488. matchnsregexp(p,sreg,up,len)
  489. char *p;
  490. struct SregExp *sreg;
  491. int up,len;
  492. /* This routine will match a sreg to a string of length 'len'. */
  493. /* The length, rather than NULL terminated is used to make a
  494.    lot of things a lot simpler */
  495. {
  496.     int res,i;
  497.  
  498.     if (sreg->sre_Flag & SRF_REPEAT) {  /* deal with repeaters. */
  499.     char not,*h;
  500.  
  501.     if (len == 0 || sreg->sre_Type == SRP_ANYCHAR) { /* always true */
  502.         res = TRUE;
  503.         goto end;
  504.     }
  505.     /* check if the lengths match up */
  506.     if (len < sreg->sre_MinLen || (sreg->sre_Flag & SRF_FIXLEN &&
  507.                (sreg->sre_MinLen == 0 || len % sreg->sre_MinLen != 0))) {
  508.         res = FALSE;
  509.         goto end;
  510.     }
  511.     not = sreg->sre_Flag & SRF_NOT;
  512.     sreg->sre_Flag &= ~(SRF_REPEAT | SRF_NOT);
  513.     if (sreg->sre_Flag & SRF_FIXLEN) { /* handle fixed lenght matches */
  514.         h = p;
  515.         while (h-p < len) {
  516.         if (!(res = matchnsregexp(h,sreg,up,sreg->sre_MinLen)))
  517.             goto end;
  518.         h += sreg->sre_MinLen;
  519.         }
  520.     } else {            /* and variable length ones */
  521.         for (i = len; i >= (sreg->sre_MinLen ? sreg->sre_MinLen : 1); i--) {
  522.         if (res = matchnsregexp(p,sreg,up,i)) {
  523.             sreg->sre_Flag |= SRF_REPEAT;
  524.             if (res = matchnsregexp(p+i,sreg,up,len-i))
  525.             break;
  526.             sreg->sre_Flag &= ~SRF_REPEAT;
  527.         }
  528.         }
  529.     }
  530.     sreg->sre_Flag |= SRF_REPEAT | not;
  531.     goto end;
  532.     }
  533.  
  534.     /* check the lengths first for quick rejection */
  535.     if (len < sreg->sre_MinLen || (sreg->sre_Flag & SRF_FIXLEN && len != sreg->sre_MinLen)) {
  536.     res = FALSE;
  537.     goto end;
  538.     }
  539.  
  540.     switch (sreg->sre_Type) {
  541.     case (SRP_SUM) :
  542.         res = matchsum(&(sreg->sre_List[0]),sreg->sre_Data.number,p,len,up);
  543.         break;
  544.     case (SRP_ONECHAR) :
  545.         res = len == 1 && (up ? *p == sreg->sre_Data.onechar :
  546.                    toupper(*p) == toupper(sreg->sre_Data.onechar));
  547.         break;
  548.     case (SRP_SETCHAR) :
  549.         res = len == 1 && matchset(sreg,*p) || (up ? FALSE :
  550.                  (isupper(*p) ? matchset(sreg,tolower(*p)) :
  551.                         matchset(sreg,toupper(*p))));
  552.         break;
  553.     case (SRP_ANYCHAR) :
  554.         res = len == 1;
  555.         break;
  556.     case (SRP_STRING) :
  557.         if (up)
  558.         res = !strncmp(p,sreg->sre_Data.string,len);
  559.         else
  560.         res = !strnicmp(p,sreg->sre_Data.string,len);
  561.         break;
  562.     case (SRP_NULL) :
  563.         res = len == 0;
  564.         break;
  565.     case (SRP_OR) :
  566.         for (i = 0; i < sreg->sre_Data.number; i++)
  567.         if (res = matchnsregexp(p,sreg->sre_List[i],up,len)) {
  568.             break;
  569.         }
  570.         break;
  571.     }
  572.  
  573. end:
  574.  
  575.     if (sreg->sre_Flag & SRF_NOT)
  576.     return !res;
  577.     else
  578.     return res;
  579. }
  580.  
  581. static int
  582. matchsum(list,num,p,len,up)
  583. struct SregExp *list[];
  584. int num,len,up;
  585. char *p;
  586. /* This routine is called by match to match the elements of a sum
  587.    of sregs.  It tries to be as effecient as possible, and keep
  588.    recursion to a minimum.  It will match any fixed length peices
  589.    at the begining and end first, then match any fixed length
  590.    peices in the middle to break the string up.  Only then does
  591.    it do the tiresome matches to the non-fixed length peices. */
  592. {
  593.     int i,res,o;
  594.  
  595.     while (num && isfixed(list[0])) {
  596.     if (!(res = matchnsregexp(p,list[0],up,list[0]->sre_MinLen)))
  597.         return FALSE;
  598.     p += list[0]->sre_MinLen;
  599.     len -= list[0]->sre_MinLen;
  600.     list++;
  601.     num--;
  602.     }
  603.     while (num && isfixed(list[num-1])) {
  604.     if (!(res = matchnsregexp(p+len-list[num-1]->sre_MinLen,list[num-1],up,
  605.                                list[num-1]->sre_MinLen)))
  606.         return FALSE;
  607.     len -= list[num-1]->sre_MinLen;
  608.     num--;
  609.     }
  610.     if (num == 0)
  611.     return TRUE;
  612.  
  613.     o = 0;
  614.     for (i = 1; i < num-1; i++) {
  615.     if (isfixed(list[i])) {
  616.         for ( ; len-o >= list[i]->sre_MinLen; o++) {
  617.         if (res = matchnsregexp(p+o,list[i],up,list[i]->sre_MinLen)) {
  618.             if (!(res = matchsum(list,i,p,o,up)))
  619.             return FALSE;
  620.             if (!(res = matchsum(list+(i+1),num-i-1,
  621.                 p+o+list[i]->sre_MinLen,len-o-list[i]->sre_MinLen,up)))
  622.             return FALSE;
  623.             return TRUE;
  624.         }
  625.         }
  626.         return FALSE;
  627.     } else
  628.         o += realen(list[i]);
  629.     }
  630.  
  631.     if (num == 1)
  632.     return matchnsregexp(p,list[0],up,len);
  633.  
  634.     for (o = len; o >= list[0]->sre_MinLen; o--)
  635.     if (matchnsregexp(p,list[0],up,o) && matchsum(list+1,num-1,p+o,len-o,up))
  636.         return TRUE;
  637.  
  638.     return FALSE;
  639. }
  640.  
  641. int
  642. iswild(p)
  643. char *p;
  644. /* this is a very simple routine, but it is externally visible.  Returns
  645.    true if the string has wildcard characters (unescaped) false if
  646.    not */
  647. {
  648.     while (onechar(&p,FALSE)) ;
  649.     return *p != 0;
  650. }
  651.  
  652. void
  653. report(i)
  654. int i;
  655. /* This routine now does set the IoErr value to more information.
  656.   For now it does nothing. */
  657. {
  658.     struct Process *myself;
  659.  
  660.     if (myself = (struct Process *)FindTask(0))
  661.     myself->pr_Result2 = i;
  662. }
  663.